﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace UI.Dendrogram
{
    public class DendrogramCanvas : Canvas
    {
        #region settings
        //private const double Edge = 10;
        //private const double leafLength = 80;
        #endregion

        #region data

        public Branch Root
        {
            get { return _Root; }
        }

        public Orientation Orientation { get; set; }
        public BinaryHierarchicalData TreeData { get; set; }
        #endregion

        #region UI
        private Branch _Root;
        private Dictionary<Branch, BinaryHierarchicalData> _BranchData;
        private Dictionary<BinaryHierarchicalData, Branch> _DataBranches;
        #endregion

        #region ctor
        public DendrogramCanvas()
        {
            
        }
        #endregion

        #region init
        public void BindData(Orientation orientation, BinaryHierarchicalData hierarchicalData)
        {
            this.Orientation = orientation;
            this.TreeData = hierarchicalData;
            this.Loaded += new RoutedEventHandler(DendrogramDocument_Loaded);
        }

        void DendrogramDocument_Loaded(object sender, RoutedEventArgs e)
        {
            this.Draw();
        }
        #endregion

        #region draw
        private void Draw()
        {
            this._BranchData = new Dictionary<Branch, BinaryHierarchicalData>();
            this._DataBranches = new Dictionary<BinaryHierarchicalData, Branch>();
            this.Children.Clear();
            Rect constraintRect=new Rect(0,0,this.Width,this.Height);
            double scaleX, scaleY;
            DendrogramUtil.DrawDendrogram(
                this, constraintRect, this.Orientation, this.TreeData,
                out scaleX, out scaleY,
                out this._DataBranches, out this._BranchData);

            foreach(Branch branch in this._BranchData.Keys)
            {
                branch.BranchUnSelected += new OnBranchUnSelected(branch_BranchUnSelected);
                branch.BranchSelected += new OnBranchSelected(branch_BranchSelected);
                branch.BranchExpanded += new OnBranchExpanded(branch_BranchExpanded);
                branch.BranchCollapsed += new OnBranchCollapsed(branch_BranchCollapsed);

                BinaryHierarchicalData treeData = this._BranchData[branch];
                if (treeData.Parent == null)
                {
                    this._Root = branch;
                }
            }
        }

        void branch_BranchUnSelected(Branch branch)
        {
            this.UnSelectBranch(branch);
        }

        void branch_BranchCollapsed(Branch branch)
        {
            this.CollapseBranch(branch);
        }

        void branch_BranchExpanded(Branch branch)
        {
            this.ExpandBranch(branch);
        }

        void branch_BranchSelected(Branch branch)
        {
            this.SelectBranch(branch);
        }
        #endregion

        #region interaction
        private void CollapseBranch(Branch branch)
        {
            //this.UnSelectBranch(this._Root);
            branch.Collapsed = true;
            if(branch.Data is BinaryHierarchicalData)
            {
                BinaryHierarchicalData treeData = (BinaryHierarchicalData) branch.Data;
                if(treeData.LeftChild !=null)
                {
                    Branch leftBranch = this._DataBranches[treeData.LeftChild];
                    this.CollapseBranch(leftBranch);
                    leftBranch.Visibility = Visibility.Collapsed;
                }
                if(treeData.RightChild !=null)
                {
                    Branch rightBranch = this._DataBranches[treeData.RightChild];
                    this.CollapseBranch(rightBranch);
                    rightBranch.Visibility = Visibility.Collapsed;
                }
            }
        }

        private void ExpandBranch(Branch branch)
        {
            //this.UnSelectBranch(this._Root);
            branch.Collapsed = false;
            if (branch.Data is BinaryHierarchicalData)
            {
                BinaryHierarchicalData treeData = (BinaryHierarchicalData)branch.Data;
                if (treeData.LeftChild != null)
                {
                    Branch leftBranch = this._DataBranches[treeData.LeftChild];
                    this.ExpandBranch(leftBranch);
                    leftBranch.Visibility = Visibility.Visible;
                }
                if (treeData.RightChild != null)
                {
                    Branch rightBranch = this._DataBranches[treeData.RightChild];
                    this.ExpandBranch(rightBranch);
                    rightBranch.Visibility = Visibility.Visible;
                }
            }
        }

        private void UnSelectBranch(Branch branch)
        {
            branch.Selected = false;
            if (branch.Data is BinaryHierarchicalData)
            {
                BinaryHierarchicalData treeData = (BinaryHierarchicalData)branch.Data;
                if (treeData.LeftChild != null)
                {
                    Branch leftBranch = this._DataBranches[treeData.LeftChild];
                    this.UnSelectBranch(leftBranch);
                }
                if (treeData.RightChild != null)
                {
                    Branch rightBranch = this._DataBranches[treeData.RightChild];
                    this.UnSelectBranch(rightBranch);
                }
            }
        }

        private void SelectBranch(Branch branch)
        {
            // this.UnSelectBranch(this._Root);
            branch.Selected = true;
            if (branch.Data is BinaryHierarchicalData)
            {
                BinaryHierarchicalData treeData = (BinaryHierarchicalData)branch.Data;
                if (treeData.LeftChild != null)
                {
                    Branch leftBranch = this._DataBranches[treeData.LeftChild];
                    this.SelectBranch(leftBranch);
                }
                if (treeData.RightChild != null)
                {
                    Branch rightBranch = this._DataBranches[treeData.RightChild];
                    this.SelectBranch(rightBranch);
                }
            }
        }
        #endregion
    }
}
